from header_common import *
from header_operations import *
from module_constants import *
from header_parties import *
from header_skills import *

####################################################################################################################
# scripts is a list of script records.
# Each script record contns the following two fields:
# 1) Script id: The prefix "script_" will be inserted when referencing scripts.
# 2) Operation block: This must be a valid operation block. See header_operations.py for reference. 
####################################################################################################################

scripts = [




  #script_party_calculate_regular_strength:
  # INPUT: 
  # param1: Party-id
  ("party_calculate_regular_strength",
   [
      (store_script_param_1, ":party"), #Party_id
      
      (assign, reg(0),0),
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (store_character_level, ":stack_strength", ":stack_troop"),
        (val_add, ":stack_strength", 5),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size, ":stack_size",":party",":i_stack"),
        (party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
        (val_sub, ":stack_size", ":num_wounded"),
        (val_mul, ":stack_strength", ":stack_size"),
        (val_add,reg(0), ":stack_strength"),
      (try_end),
    ]),

  #script_party_calculate_strength:
  # INPUT: 
  # param1: Party-id  

  ("party_calculate_strength",
   [
      (store_script_param_1, ":party"), #Party_id
      
      (assign, reg(0),0),
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (store_character_level, ":stack_strength", ":stack_troop"),
        (val_add, ":stack_strength", 5),
        (try_begin),
          (neg|troop_is_hero, ":stack_troop"),
          (party_stack_get_size, ":stack_size",":party",":i_stack"),
          (party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
          (val_sub, ":stack_size", ":num_wounded"),
          (val_mul, ":stack_strength", ":stack_size"),
        (try_end),
        (val_add,reg(0), ":stack_strength"),
      (try_end),
    ]),

  #script_party_calculate_loot:
  # INPUT: 
  # param1: Party-id  
  # param2: Allied Party-id
  # Returns num looted items in reg(0)

  ("party_calculate_loot",
   [
      (store_script_param_1, ":party"), #Party_id
      (store_script_param_2, ":allied_party"), #Party_id


      (call_script, "script_calculate_party_shares", ":allied_party"),
      (assign, ":num_player_party_shares", reg0),
      (assign, ":num_ally_shares", reg1),
      (store_add, ":num_shares",  ":num_player_party_shares", ":num_ally_shares"),

      (assign, ":num_shares",10),
      #Calculate player loot probability
      (assign, ":loot_proboability", 100),
      (val_mul, ":loot_proboability", 10),
      (val_div, ":loot_proboability", ":num_shares"),

      #Now loot the defeated party
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size, ":stack_size",":party",":i_stack"),
        (try_for_range, ":j", 0, ":stack_size"),
          (troop_loot_troop,"trp_temp_troop",":stack_troop",":loot_proboability"),
        (try_end),
      (try_end),
      (assign, ":num_looted_items",0),
      (troop_get_inventory_capacity, ":inv_cap", "trp_temp_troop"),
      (try_for_range, ":i_slot", 0, ":inv_cap"),
        (troop_get_inventory_slot, ":item_id", "trp_temp_troop", ":i_slot"),
        (ge, ":item_id", 0),
        (val_add, ":num_looted_items",1),
      (try_end),
      (assign, reg0, ":num_looted_items"),
    ]),

  #script_calculate_party_shares:
  # INPUT: 
  # param1: Allied Party-id
  # Returns number of player party shares in reg0
  # Returns number of allied party shares in reg1

  ("calculate_party_shares",
   [
      (store_script_param_1, ":allied_party"), #Party_id
      
      (assign, ":num_player_party_shares",10),
      # Add shares for player's party
      (party_get_num_companion_stacks, ":num_stacks","p_main_party"),
      (try_for_range, ":i_stack", 1, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop","p_main_party",":i_stack"),
        (try_begin),
          (neg|troop_is_hero, ":stack_troop"),
          (party_stack_get_size, ":stack_size","p_main_party",":i_stack"),
          (val_add, ":num_player_party_shares", ":stack_size"),
        (else_try),
          (val_add, ":num_player_party_shares", 10),
        (try_end),
      (try_end),

      (assign, ":num_ally_shares",0),
      # Now add shares for the allied party
      (try_begin),
        (gt, ":allied_party", 0),
        (assign, ":num_ally_shares", 10),
        (party_get_num_companion_stacks, ":num_stacks",":allied_party"),
        (try_for_range, ":i_stack", 1, ":num_stacks"),
          (party_stack_get_troop_id,     ":stack_troop",":allied_party",":i_stack"),
          (try_begin),
            (neg|troop_is_hero, ":stack_troop"),
            (party_stack_get_size, ":stack_size",":allied_party",":i_stack"),
            (val_add, ":num_ally_shares", ":stack_size"),
          (else_try),
            (val_add, ":num_ally_shares", 10),
          (try_end),
        (try_end),
      (try_end),

      (assign, reg0, ":num_player_party_shares"),
      (assign, reg1, ":num_ally_shares"),
      
    ]),

  #script_party_give_xp_and_gold:
  # INPUT: 
  # param1: destroyed Party-id  
  # param2: Allied Party-id
  # calculates and gives player paty's share of gold and xp.

  ("party_give_xp_and_gold",
   [
      (store_script_param_1, ":party"), #Party_id
      (store_script_param_2, ":allied_party"), #Party_id

      (call_script, "script_calculate_party_shares", ":allied_party"),
      (assign, ":num_player_party_shares", reg0),
      (assign, ":num_ally_shares", reg1),
      (store_add, ":num_total_shares",  ":num_player_party_shares", ":num_ally_shares"),

      (assign, ":total_gain", 0),
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size, ":stack_size",":party",":i_stack"),
        (store_character_level, ":level", ":stack_troop"),
        (store_add, ":gain", ":level", 10),
        (val_mul, ":gain", ":gain"),
        (val_div, ":gain", 10),
        (store_mul, ":stack_gain", ":gain", ":stack_size"),
        (val_add, ":total_gain", ":stack_gain"),
      (try_end),

      (store_mul, ":player_party_xp_gain", ":total_gain", ":num_player_party_shares"),
      (val_div, ":player_party_xp_gain", ":num_total_shares"),
      (store_random_in_range, ":r", 0, 100),
      (val_mul, ":player_party_xp_gain", ":r"),
      (val_div, ":player_party_xp_gain", 100),
      
      (party_add_xp, "p_main_party", ":player_party_xp_gain"),

      (store_mul, ":player_gold_gain", ":total_gain", 10),
      (val_div, ":player_gold_gain", ":num_total_shares"),
      (store_random_in_range, ":r", 0, 100),
      (val_mul, ":player_gold_gain", ":r"),
      (val_div, ":player_gold_gain", 100),
      (val_div, ":player_gold_gain", 5),

#add gold now
      (party_get_num_companion_stacks, ":num_stacks","p_main_party"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop","p_main_party",":i_stack"),
        (try_begin),
          (troop_is_hero, ":stack_troop"),
          (troop_add_gold, ":stack_troop", ":player_gold_gain"),
        (try_end),
      (try_end),
    ]),


  #script_setup_troop_meeting:
  # INPUT: 
  # param1: troop_id with which meeting will be made.
  # param2: troop_dna (optional)

  ("setup_troop_meeting",
   [
       (store_script_param_1, ":meeting_troop"), 
       (store_script_param_2, ":troop_dna"), 
       (modify_visitors_at_site,"scn_conversation_scene"),(reset_visitors),
       (set_visitor,0,"trp_player"),
#       (party_stack_get_troop_dna,":troop_dna",":meeting_party",0),
       (set_visitor,17,":meeting_troop",":troop_dna"),
       (set_jump_mission,"mt_conversation_encounter"),
       (jump_to_scene,"scn_conversation_scene"),
       (change_screen_map_conversation, ":meeting_troop"),
    ]),

  #script_setup_party_meeting:
  # INPUT: 
  # param1: Party-id with which meeting will be made.

  ("setup_party_meeting",
   [
       (store_script_param_1, ":meeting_party"), 
       (modify_visitors_at_site,"scn_conversation_scene"),(reset_visitors),
       (set_visitor,0,"trp_player"),
       (party_stack_get_troop_id, ":meeting_troop",":meeting_party",0),
       (party_stack_get_troop_dna,":troop_dna",":meeting_party",0),
       (set_visitor,17,":meeting_troop",":troop_dna"),
       (set_jump_mission,"mt_conversation_encounter"),
       (jump_to_scene,"scn_conversation_scene"),
       (change_screen_map_conversation, ":meeting_troop"),
    ]),

  #script_party_remove_all_companions:
  # INPUT: 
  # param1: Party-id from which  companions will be removed.
  # "$g_move_heroes" : controls if heroes will also be removed.

  ("party_remove_all_companions",
   [
      (store_script_param_1, ":party"), #Source Party_id
      (party_get_num_companion_stacks, ":num_companion_stacks",":party"),
      (try_for_range_backwards, ":stack_no", 0, ":num_companion_stacks"),
        (party_stack_get_troop_id,   ":stack_troop",":party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_stack_get_size,  ":stack_size",":party",":stack_no"),
        (party_remove_members, ":party", ":stack_troop",  ":stack_size"),
      (try_end),
    ]),

  #script_party_remove_all_prisoners:
  # INPUT: 
  # param1: Party-id from which  prisoners will be removed.
  # "$g_move_heroes" : controls if heroes will also be removed.

  ("party_remove_all_prisoners",
   [
      (store_script_param_1, ":party"), #Source Party_id
      (party_get_num_prisoner_stacks, ":num_prisoner_stacks",":party"),
      (try_for_range_backwards, ":stack_no", 0, ":num_prisoner_stacks"),
        (party_prisoner_stack_get_troop_id,   ":stack_troop",":party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_prisoner_stack_get_size, ":stack_size",":party",":stack_no"),
        (party_remove_prisoners, ":party", ":stack_troop", ":stack_size"),
      (try_end),
    ]),

  #script_party_add_party_companions:
  # INPUT: 
  # param1: Party-id to add the second part 
  # param2: Party-id which will be added to the first one.
  # "$g_move_heroes" : controls if heroes will also be added.

  ("party_add_party_companions",
   [
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (party_get_num_companion_stacks, ":num_stacks",":source_party"),
      (try_for_range, ":stack_no", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_stack_get_size,         ":stack_size",":source_party",":stack_no"),
        (party_add_members, ":target_party", ":stack_troop", ":stack_size"),
      (try_end),
    ]),

  #script_party_add_party_prisoners:
  # INPUT: 
  # param1: Party-id to add the second party
  # param2: Party-id which will be added to the first one.
  # "$g_move_heroes" : controls if heroes will also be added.

  ("party_add_party_prisoners",
   [
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (party_get_num_prisoner_stacks, ":num_stacks",":source_party"),
      (try_for_range, ":stack_no", 0, ":num_stacks"),
        (party_prisoner_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_prisoner_stack_get_size,         ":stack_size",":source_party",":stack_no"),
        (party_add_members, ":target_party", ":stack_troop", ":stack_size"),
      (try_end),
    ]),
  
  #script_party_prisoners_add_party_companions:
  # INPUT: 
  # param1: Party-id to add the second part 
  # param2: Party-id which will be added to the first one.
  # "$g_move_heroes" : controls if heroes will also be added.

  ("party_prisoners_add_party_companions",
   [
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (party_get_num_companion_stacks, ":num_stacks",":source_party"),
      (try_for_range, ":stack_no", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_stack_get_size,         ":stack_size",":source_party",":stack_no"),
        (party_add_prisoners, ":target_party", ":stack_troop", ":stack_size"),
      (try_end),
    ]),

  #script_party_prisoners_add_party_prisoners:
  # INPUT: 
  # param1: Party-id to add the second part 
  # param2: Party-id which will be added to the first one.
  # "$g_move_heroes" : controls if heroes will also be added.

  ("party_prisoners_add_party_prisoners",
   [
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (party_get_num_prisoner_stacks, ":num_stacks",":source_party"),
      (try_for_range, ":stack_no", 0, ":num_stacks"),
        (party_prisoner_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (this_or_next|neg|troop_is_hero, ":stack_troop"),
        (eq, "$g_move_heroes", 1),
        (party_prisoner_stack_get_size,         ":stack_size",":source_party",":stack_no"),
        (party_add_prisoners, ":target_party", ":stack_troop", ":stack_size"),
      (try_end),
    ]),

  #party_add_party:
  # INPUT: 
  # param1: Party-id to add the second part 
  # param2: Party-id which will be added to the first one.
  # "$g_move_heroes" : controls if heroes will also be added.

  ("party_add_party",
   [
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (call_script, "script_party_add_party_companions",          ":target_party", ":source_party"),
      (call_script, "script_party_prisoners_add_party_prisoners", ":target_party", ":source_party"),
    ]),


  #script_party_copy:
  # INPUT: 
  # param1: Party-id to copy the second party 
  # param2: Party-id which will be copied to the first one.

  ("party_copy",
   [
      (assign, "$g_move_heroes", 1),
      (store_script_param_1, ":target_party"), #Target Party_id
      (store_script_param_2, ":source_party"), #Source Party_id
      (party_clear, ":target_party"),
      (call_script, "script_party_add_party", ":target_party", ":source_party"),
    ]),


  #script_clear_party_group:
  # INPUT: 
  # param1: Party-id of the root of the group.
  # This script will clear the root party and all parties attached to it recursively.

  ("clear_party_group",
   [
      (store_script_param_1, ":root_party"),
      (party_clear, ":root_party"),
      (party_get_num_attached_parties, ":num_attached_parties", ":root_party"),
      (try_for_range, ":attached_party_rank", 0, ":num_attached_parties"),
         (party_get_attached_party, ":attached_party", ":root_party", ":attached_party_rank"),
         (call_script, "script_clear_party_group", ":attached_party"),
      (try_end),
   ]),

  #script_get_nonempty_party_in_group:
  # INPUT: 
  # param1: Party-id of the root of the group.
  # OUTPUT: reg0: nonempy party-id

  ("get_nonempty_party_in_group",
   [
       
      (store_script_param_1, ":party_no"),
      (party_get_num_companions, ":num_companions", ":party_no"),
      (try_begin),
        (gt, ":num_companions", 0),
        (assign, reg0, ":party_no"),
      (else_try),
        (assign, reg0, -1),

        (party_get_num_attached_parties, ":num_attached_parties", ":party_no"),
        (try_for_range, ":attached_party_rank", 0, ":num_attached_parties"),
          (lt, reg0, 0),
          (party_get_attached_party, ":attached_party", ":party_no", ":attached_party_rank"),
          (call_script, "script_get_nonempty_party_in_group", ":attached_party"),
        (try_end),
      (try_end),
   ]),

  #script_collect_prisoners_from_empty_parties:
  # INPUT: 
  # param1: Party-id of the root of the group.
  # param2: Party to collect prisoners in.
  # make sure collection party is cleared before calling this.

  ("collect_prisoners_from_empty_parties", 
   [
      (store_script_param_1, ":party_no"),
      (store_script_param_1, ":collection_party"),
     
      (party_get_num_companions, ":num_companions", ":party_no"),
      (try_begin),
        (eq, ":num_companions", 0), #party is empty (has no companions). Collect its prisoners.
        (party_get_num_prisoner_stacks, ":num_stacks",":party_no"),
        (try_for_range, ":stack_no", 0, ":num_stacks"),
           (party_prisoner_stack_get_troop_id,     ":stack_troop",":party_no",":stack_no"),
           (troop_is_hero, ":stack_troop"),
           (party_add_members, ":collection_party", ":stack_troop", 1),
        (try_end),
      (try_end),
      (party_get_num_attached_parties, ":num_attached_parties", ":party_no"),
      (try_for_range, ":attached_party_rank", 0, ":num_attached_parties"),
         (party_get_attached_party, ":attached_party", ":party_no", ":attached_party_rank"),
         (call_script, "script_collect_prisoners_from_empty_parties", ":attached_party", ":collection_party"),
      (try_end),
   ]),



  #script_print_party_to_s0:
  # INPUT: 
  # param1: Party-id

  #OUTPUT:
  # string register 0.
    
  ("print_casualties_to_s0",
   [
      (store_script_param_1, ":party"), #Party_id
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (store_sub, ":last_stack", ":num_stacks", 1),
      (str_store_string, s62, "str_none"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
#        
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (party_stack_get_size,         ":stack_size",":party",":i_stack"),
        (party_stack_get_num_wounded,  ":stack_num_wounded", ":party",":i_stack"),
        (store_sub,  ":stack_num_killed", ":stack_size", ":stack_num_wounded"),
        (str_store_troop_name_by_count, s61, ":stack_troop", ":stack_size"),
        (try_begin), #print troop type to s
          (troop_is_hero, ":stack_troop"),
          (str_store_string_reg, s63, s61),
        (else_try),
          (assign, reg60, ":stack_size"),
          (str_store_string, s63, "str_reg60_s61"),
        (try_end),
        (assign, reg60, ":stack_num_wounded"),
        (str_store_string, s50, "str_reg60_wounded"),
        (assign, reg60, ":stack_num_killed"),
        (str_store_string, s51, "str_reg60_killed"),
        (try_begin), #print wounded/killed info to s59
          (eq, ":stack_num_wounded", 0), #all killed
          (str_store_string, s58, "str_parenthesis_killed"),
        (else_try),
          (eq, ":stack_num_killed", 0),
          (str_store_string, s58, "str_parenthesis_wounded"),
        (else_try),
          (str_store_string, s58, "str_parenthesis_s50_comma_s51"),
        (try_end),
        (str_store_string_reg, s50, s63),
        (str_store_string_reg, s51, s58),
        (str_store_string, s51, "str_s50_s51"),
        (try_begin),
          (eq, ":i_stack", 0),
          (str_store_string_reg, s62, s51),
        (else_try),
          (eq, ":i_stack", ":last_stack"),
          (str_store_string_reg, s50, s62),
          (str_store_string, s62, "str_s50_comma_s51"),
        (else_try),
          (str_store_string_reg, s50, s62),
          (str_store_string, s62, "str_s50_comma_s51"),
        (try_end),
      (try_end),
      (try_begin),
        (eq,  ":num_stacks", 0),
        (str_store_string, s62, "str_none"),
      (try_end),
      
#      (try_begin),
#        (gt, ":num_stacks", 0),
#        (str_store_string_reg, s50, s62),
#        (str_store_string_reg, s62, "str_s50_period"),
#      (try_end),
      (str_store_string_reg, s0, s62),
    ]),


  #script_print_party_to_s0:
  # INPUT: 
  # param1: Party-id

  #OUTPUT:
  # string register 0.
    
  ("print_party_to_s0",
   [
      (store_script_param_1, ":party"), #Party_id
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (str_store_string, s50, "str_none"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (party_stack_get_size,         ":stack_size",":party",":i_stack"),
        (str_store_troop_name_by_count, s61, ":stack_troop", ":stack_size"),
        (try_begin),
          (troop_is_hero, ":stack_troop"),
          (str_store_string_reg, s51, s61),
        (else_try),
          (assign, reg60, ":stack_size"),
          (str_store_string, s63, "str_reg60_s61"),
        (try_end),
        (try_begin),
          (eq, ":i_stack", 0),
          (str_store_string_reg, s50, s51),
        (else_try),
          (str_store_string, s50, "str_s50_comma_s51"),
        (try_end),
      (try_end),
      (str_store_string_reg, s0, s50),
    ]),


  #script_party_count_fit_regulars:
  # Returns the number of unwounded regular companions in a party
  # INPUT: 
  # param1: Party-id 

  ("party_count_fit_regulars",
   [
      (store_script_param_1, ":party"), #Party_id
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (assign, reg0, 0),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size,         ":stack_size",":party",":i_stack"),
        (party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
        (val_sub, ":stack_size", ":num_wounded"),
        (val_add, reg0, ":stack_size"),
      (try_end),
    ]),

   
  #script_party_count_fit_for_battle:
  # Returns the number of unwounded regular companions in a party
  # INPUT: 
  # param1: Party-id 

  ("party_count_fit_for_battle",
   [
      (store_script_param_1, ":party"), #Party_id
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (assign, reg0, 0),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (assign, ":num_fit",0),
        (try_begin),
          (troop_is_hero, ":stack_troop"),
          (store_troop_health, ":troop_hp", ":stack_troop"),
          (ge,  ":troop_hp", 20),
          (assign, ":num_fit",1),
        (else_try),
          (party_stack_get_size,         ":num_fit",":party",":i_stack"),
          (party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
          (val_sub, ":num_fit", ":num_wounded"),
        (try_end),
        (val_add, reg0, ":num_fit"),
      (try_end),
    ]),

  #script_get_stack_with_rank:
  # Returns the stack no, containing unwounded regular companions with rank rank.
  # INPUT: 
  # param1: Party-id 
  # param2: rank

  ("get_stack_with_rank",
   [
      (store_script_param_1, ":party"), #Party_id
      (store_script_param_2, ":rank"), #Rank
      (party_get_num_companion_stacks, ":num_stacks",":party"),
      (assign, reg(0), -1),
      (assign, ":num_total", 0),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (eq, reg(0), -1), #continue only if we haven't found the result yet.
        (party_stack_get_troop_id,     ":stack_troop",":party",":i_stack"),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size,         ":stack_size",":party",":i_stack"),
        (party_stack_get_num_wounded,  ":num_wounded",":party",":i_stack"),
        (val_sub, ":stack_size", ":num_wounded"),
        (val_add, ":num_total", ":stack_size"),
        (try_begin),
          (lt, ":rank", ":num_total"),
          (assign, reg(0), ":i_stack"),
        (try_end),
      (try_end),
    ]),

  #script_inflict_casualties_to_party:
  # INPUT: 
  # param1: Party-id
  # param2: number of rounds

  #OUTPUT:
  # This script doesn't return a value but populates the parties p_temp_wounded and p_temp_killed with the wounded and killed.
  #Example:
  #  (script_inflict_casualties_to_party, "_p_main_party" ,50),
  #  Simulate 50 rounds of casualties to main_party.
    
  ("inflict_casualties_to_party",
   [
      (party_clear, "p_temp_casualties"),
      (store_script_param_1, ":party"), #Party_id
      (call_script, "script_party_count_fit_regulars", ":party"),
      (assign, ":num_fit_regulars", reg(0)), #reg(47) = number of fit regulars.
      (store_script_param_2, ":num_attack_rounds"), #number of attacks
      (try_for_range, ":attack_round", 0, ":num_attack_rounds"),
        (gt, ":num_fit_regulars", 0), #attack troop with rank reg(46)
        (store_random_in_range, ":attacked_troop_rank", 0 , ":num_fit_regulars"), #attack troop with rank reg(46)
        (call_script, "script_get_stack_with_rank", ":party", ":attacked_troop_rank"),
        (assign, ":attacked_stack", reg(0)), #reg(53) = stack no to attack.
        (party_stack_get_troop_id,     ":attacked_troop",":party",":attacked_stack"),
        (store_character_level, ":troop_toughness", ":attacked_troop"),
        (val_add, ":troop_toughness", 5),  #troop-toughness = level + 5
        (assign, ":casualty_chance", 10000),
        (val_div, ":casualty_chance", ":troop_toughness"), #dying chance
        (try_begin),
          (store_random_in_range, ":rand_num", 0 ,10000),
          (lt, ":rand_num", ":casualty_chance"), #check chance to be a casualty
          (store_random_in_range, ":rand_num2", 0, 2), #check if this troop will be wounded or killed
          (try_begin),
            (lt, ":rand_num2", 1), #wounded
            (party_add_members, "p_temp_casualties", ":attacked_troop", 1),
            (party_wound_members, "p_temp_casualties", ":attacked_troop", 1),
            (party_wound_members, ":party", ":attacked_troop", 1),
          (else_try), #killed
            (party_add_members, "p_temp_casualties", ":attacked_troop", 1),
            (party_remove_members, ":party", ":attacked_troop", 1),
          (try_end),
          (val_sub, ":num_fit_regulars", 1), #adjust number of fit regulars.
        (try_end),
      (try_end),
    ]),


  #script_move_members_with_ratio:
  # INPUT: 
  # param1: Source Party-id
  # param2: Target Party-id
  # pin_number = ratio of members to move, multiplied by 1000

  #OUTPUT:
  # This script doesn't return a value but moves some of the members of source party to target party according to the given ratio.
  ("move_members_with_ratio",
   [
      (store_script_param_1, ":source_party"), #Source Party_id
      (store_script_param_2, ":target_party"), #Target Party_id
      (party_get_num_prisoner_stacks, ":num_stacks",":source_party"),
      (try_for_range_backwards, ":stack_no", 0, ":num_stacks"),
        (party_prisoner_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (party_prisoner_stack_get_size,    ":stack_size",":source_party",":stack_no"),
        (store_mul, ":number_to_move",":stack_size","$pin_number"),
        (val_div, ":number_to_move", 1000),
        (val_add, ":number_to_move", 1),
        (party_remove_prisoners, ":source_party", ":stack_troop", ":number_to_move"),
        (assign, ":number_moved", reg0),
        (party_add_prisoners, ":target_party", ":stack_troop", ":number_moved"),
      (try_end),
      (party_get_num_companion_stacks, ":num_stacks",":source_party"),
      (try_for_range_backwards, ":stack_no", 0, ":num_stacks"),
        (party_stack_get_troop_id,     ":stack_troop",":source_party",":stack_no"),
        (party_stack_get_size,    ":stack_size",":source_party",":stack_no"),
        (store_mul, ":number_to_move",":stack_size","$pin_number"),
        (val_div, ":number_to_move", 1000),
        (val_add, ":number_to_move", 1),
        (party_remove_members, ":source_party", ":stack_troop", ":number_to_move"),
        (assign, ":number_moved", reg0),
        (party_add_members, ":target_party", ":stack_troop", ":number_moved"),
      (try_end),
    ]),

# For the moment, this simply sets the town faction the same as that of its lord.
# We may do more sophisticated things here later.
  ("reassign_faction_of_town",
   [
      (store_script_param_1, ":town"),
      (party_get_slot,":town_fac", ":town", slot_town_belongs_to_kingdom),
      (ge, ":town_fac", 1), #check if valid...
      (party_set_faction,":town",":town_fac"),
    ]),

# script_count_parties_of_faction_and_party_type:
# counts number of active parties with a template and faction.
# Input: arg1 = faction_no, arg2 = party_type
# Output: reg0 = count
 
  ("count_parties_of_faction_and_party_type",
   [
       (store_script_param_1, ":faction_no"),
       (store_script_param_2, ":party_type"),
       (assign, reg0, 0),
       (try_for_parties, ":party_no"),
         (party_is_active, ":party_no"),
         (party_get_slot, ":cur_party_type", ":party_no", slot_party_type),
         (eq, ":cur_party_type", ":party_type"),
         (store_faction_of_party, ":cur_faction", ":party_no"),
         (eq, ":cur_faction", ":faction_no"),
         (val_add, reg0, 1),
       (try_end),
    ]),



  #script_select_random_town:
  # This script selects a random town in range [towns_begin, towns_end)
  # INPUTS: 
  # none

  #OUTPUT:
  # $pout_town: id of the selected random town
  ("select_random_town",
   [
      (assign, ":num_towns", towns_end),
      (val_sub,":num_towns", towns_begin),
      (store_random, ":random_town", ":num_towns"),
      (val_add,":random_town", towns_begin),
      (assign, "$pout_town", ":random_town"),
    ]),

  ("select_random_spawn_point",
   [
      (assign, reg(20), spawn_points_end),
      (val_sub,reg(20), spawn_points_begin),
      (store_random, reg(21), reg(20)),
      (val_add,reg(21), spawn_points_begin),
      (assign, "$pout_town", reg(21)),
    ]),
  
  #script_select_faction_town:
  # This script selects a random town in range [towns_begin, towns_end)
  # such that faction of the town is equal to given_faction
  # INPUT: 
  # $pin_faction: given_faction

  #OUTPUT:
  # This script may return false if there is no matching town.
  # $pout_town: id of the selected random town
  ("select_faction_town",
   [
      # First count num matching spawn points 
      (assign, reg(24), 0),
      (try_for_range,reg(25), towns_begin, towns_end),
        (store_faction_of_party, reg(23), reg(25)),
        (eq, reg(23), "$pin_faction"),
        (val_add, reg(24), 1),
      (end_try,0),
       # reg4 now holds num towns of this faction.
      (gt, reg(24), 0), #Fail if there are no towns
      (store_random, reg(26), reg(24)),
      
      (assign, reg(24), 0), # reg24 = num points of this faction.
      (try_for_range,reg(25), towns_begin, towns_end),
        (store_faction_of_party, reg(23), reg(25)),
        (eq, reg(23), "$pin_faction"),
        (try_begin,0),
          (eq, reg(24), reg(26)),
          (assign, "$pout_town", reg(25)), # result is this town
        (end_try,0),
        (val_add, reg(24), 1),
      (end_try,0),
    ]),

  ("select_faction_spawn_point",
   [
      # First count num matching spawn points 
      (assign, reg(24), 0),
      (try_for_range,reg(25), spawn_points_begin, spawn_points_end),
        (store_faction_of_party, reg(23), reg(25)),
        (eq, reg(23), "$pin_faction"),
        (val_add, reg(24), 1),
      (end_try,0),
       # reg4 now holds num towns of this faction.
      (gt, reg(24), 0), #Fail if there are no towns
      (store_random, reg(26), reg(24)),
      
      (assign, reg(24), 0), # reg24 = num points of this faction.
      (try_for_range,reg(25), spawn_points_begin, spawn_points_end),
        (store_faction_of_party, reg(23), reg(25)),
        (eq, reg(23), "$pin_faction"),
        (try_begin,0),
          (eq, reg(24), reg(26)),
          (assign, "$pout_town", reg(25)), # result is this town
        (end_try,0),
        (val_add, reg(24), 1),
      (end_try,0),
    ]),


  #script_spawn_party_at_random_town:
  # This script selects a random town in range [towns_begin, towns_end)
  # such that faction of the town is equal to given_faction
  # and spawns a new party there.
  # INPUT: 
  # $pin_faction: given_faction
  # $pin_party_template: given_party_template

  #OUTPUT:
  # This script may return false if party can not be spawned.
  # $pout_party: id of the spawned party
  ("spawn_party_at_random_town",
   [
       (call_script,"script_select_random_spawn_point"),
       (set_spawn_radius,1),
       (spawn_around_party,"$pout_town","$pin_party_template"),
       (assign, "$pout_party", reg(0)),
    ]),

  #script_spawn_party_at_faction_town:
  # This script selects a random town in range [towns_begin, towns_end)
  # such that faction of the town is equal to given_faction
  # and spawns a new party there.
  # INPUT: 
  # $pin_faction: given_faction
  # $pin_party_template: given_party_template

  #OUTPUT:
  # This script may return false if party can not be spawned.
  # $pout_party: id of the spawned party
  ("spawn_party_at_faction_town",
   [
       (call_script,"script_select_faction_spawn_point"),
       (set_spawn_radius,1),
       (spawn_around_party,"$pout_town","$pin_party_template"),
       (assign, "$pout_party", reg(0)),
    ]),

  #script_spawn_party_at_random_town_if_below_limit:
  # This script checks if number of parties 
  # of specified template is less than limit,
  # If so, it selects a random town in range [towns_begin, towns_end)
  # and spawns a new party there.
  # INPUT: 
  # $pin_party_template: given_party_template
  # $pin_limit: limit value

  #OUTPUT:
  # $pout_party: id of the spawned party
  # $pout_town: id of the selected faction town
  # Note:
  # This script may return false if number of parties 
  # of specified template is greater or equal to limit,
  # or if party can not be spawned.
  ("spawn_party_at_random_town_if_below_limit",
   [
       (store_num_parties_of_template, reg(22), "$pin_party_template"),
       (lt,reg(22),"$pin_limit"), #check if we are below limit.
       (call_script,"script_select_random_spawn_point"),
       (set_spawn_radius,1),
       (spawn_around_party,"$pout_town","$pin_party_template"),
       (assign, "$pout_party", reg(0)),
    ]),

  #script_spawn_party_at_faction_town_if_below_limit:
  # This script checks if number of parties 
  # of specified template is less than limit,
  # If so, it selects a random town in range [towns_begin, towns_end)
  # such that faction of the town is equal to given_faction
  # and spawns a new party there.
  # INPUT: 
  # $pin_faction: given_faction
  # $pin_party_template: given_party_template
  # $pin_limit: limit value

  #OUTPUT:
  # $pout_party: id of the spawned party
  # $pout_town: id of the selected faction town
  # Note:
  # This script may return false if number of parties 
  # of specified template is greater or equal to limit,
  # or if party can not be spawned.
  ("spawn_party_at_faction_town_if_below_limit",
   [
       (store_num_parties_of_template, reg(22), "$pin_party_template"),
       (lt,reg(22),"$pin_limit"), #check if we are below limit.
       (call_script,"script_select_faction_spawn_point"),
       (set_spawn_radius,1),
       (spawn_around_party,"$pout_town","$pin_party_template"),
       (assign, "$pout_party", reg(0)),
    ]),

# script_shuffle_scene_slots:
# Shuffles a range of slots of a given troop.
# Used for exploiting a troop as an array.
# Input: $pin_troop, arg1 = slot_begin, arg2 = slot_end
  ("shuffle_troop_slots",
   [
     (store_script_param_1, ":slots_begin"),
     (store_script_param_2, ":slots_end"),
     (try_for_range, ":cur_slot_no", ":slots_begin", ":slots_end"),
       (store_random_in_range, ":random_slot_no", ":slots_begin", ":slots_end"), #reg(58) = random slot. Now exchange slots reg(57) and reg(58)
       (troop_get_slot, ":cur_slot_value", "$pin_troop", ":cur_slot_no"), #temporarily store the value in slot reg(57) in reg(59)
       (troop_get_slot, ":random_slot_value", "$pin_troop", ":random_slot_no"), #temporarily store the value in slot reg(58) in reg(60)
       (troop_set_slot, "$pin_troop", ":cur_slot_no", ":random_slot_value"), # Now exchange the two...
       (troop_set_slot, "$pin_troop", ":random_slot_no", ":cur_slot_value"), 
     (try_end),
    ]),


# script_instantiate_deliver_message_quest:
# Input: arg1 = quest_id
# Destroys registers: reg(55) through reg(60)  
  ("instantiate_deliver_message_quest",
   [
       (assign, reg(58), -1),
       (try_for_range, reg(59),towns_begin,towns_end),
         (neq, reg(59), "$g_encountered_party"),
         (store_faction_of_party, reg(60), reg(59)),
         (store_faction_of_party, reg(61), "$g_encountered_party"),
         (eq, reg(60), reg(61)),
         (assign, reg(58), reg(59)),
       (try_end),
    ]),


# script_check_kingdom_quest_possible:
# Input: arg1 = quest_id
# Destroys registers: reg(55) through reg(60)  
  ("instantiate_kingdom_quest",
   [
      (store_script_param_1, reg(60)),
      (assign, reg(62), 0),
      (try_begin),
        (eq, reg(60), "qst_deliver_message"),
        (try_for_range, reg(59),towns_begin,towns_end),
        (try_end),
      (try_end),
      (eq, reg(62), 1), # Fail if reg(62) is not 1
    ]),

# script_get_kingdom_quest:
# Input: $pin_scene, arg1 = slot_begin, arg2 = slot_end
# Output: $pout_quest  
# Destroys registers: reg(55) through reg(60)  
  ("get_kingdom_quest",
   [
      (assign, "$pout_quest", -1),
      (try_for_range, reg(55), 0, 20), #Repeat trial ten times
        (eq, "$pout_quest", -1),
        (store_random_in_range,reg(56),lord_quests_begin,lord_quests_end),
        (try_begin),
          (eq, reg(56), "qst_deliver_message"),
          #search for target lord)
          (assign, "$pout_quest", reg(56)),
        (try_end),
      (try_end),
    ]),

# script_get_town_max_siege_resistance
# Input: arg1 = town_no
# Output: reg0 = maximum siege resistance
  ("get_town_max_siege_resistance",
   [
       #TODO: Fix this
      (assign, reg0, 3),
    ]),

# script_change_town_faction
# Input: arg1 = town_no, arg2 = new_faction
  ("change_town_faction",
   [
       (store_script_param_1, ":town_no"),
       (store_script_param_2, ":faction_no"),
       (party_get_slot, ":old_faction", ":town_no", slot_town_belongs_to_kingdom),
       (party_set_slot, ":town_no", slot_town_belongs_to_kingdom, ":faction_no"),
       (party_set_faction, ":town_no", ":faction_no"),
       (assign, reg0, 3),
    ]),



# script_get_closest_center_of_faction
# Input: arg1 = party_no, arg2 = kingdom_no
# Output: reg0 = party_no (of town or castle)
  ("get_closest_center_of_faction",
   [
       (store_script_param_1, ":party_no"),
       (store_script_param_2, ":kingdom_no"),
       (assign, ":min_distance", 9999999),
       (assign, reg0, -1),
       (try_for_range, ":center_no", centers_begin, centers_end),
         (store_faction_of_party, ":faction_no", ":center_no"),
         (eq, ":faction_no", ":kingdom_no"),
         (store_distance_to_party_from_party, ":party_distance", ":party_no", ":center_no"),
         (lt, ":party_distance", ":min_distance"),
         (assign, ":min_distance", ":party_distance"),
         (assign, reg0, ":center_no"),
       (try_end),
    ]),



# script_party_wound_all_members
# Input: arg1 = party_no
  ("party_wound_all_members",
   [
      (store_script_param_1, ":party_no"),
      
      (party_get_num_companion_stacks, ":num_stacks",":party_no"),
      (try_for_range, ":i_stack", 0, ":num_stacks"),
        (party_stack_get_troop_id, ":stack_troop",":party_no",":i_stack"),
        (neg|troop_is_hero, ":stack_troop"),
        (party_stack_get_size, ":stack_size",":party_no",":i_stack"),
        (party_wound_members, ":party_no", ":stack_troop", ":stack_size"),
      (try_end),
    ]),



# script_calculate_battle_advantage
# Input: arg1 = enemy_party_id, arg2 = ally_party_id
# Output: reg0 = battle advantage
  ("calculate_battle_advantage",
   [
     (store_script_param_1, ":enemy_party_no"),
     (store_script_param_2, ":ally_party_no"),

      
     (call_script, "script_party_count_fit_for_battle", "p_main_party"),
     (assign, ":friend_count", reg(0)),

     (party_get_skill_level, ":player_party_tactics",  "p_main_party", skl_tactics),

     (try_begin),
       (gt, ":ally_party_no", 0),
       (call_script, "script_party_count_fit_for_battle", ":ally_party_no"),
       (val_add, ":friend_count", reg(0)),

       (party_get_skill_level, ":ally_party_tactics",  ":ally_party_no", skl_tactics),
       (val_max, ":player_party_tactics", ":ally_party_tactics"),
     (try_end),

     (call_script, "script_party_count_fit_for_battle", ":enemy_party_no"),
     (assign, ":enemy_count", reg(0)),

     (party_get_skill_level, ":enemy_party_tactics",  ":enemy_party_no", skl_tactics),

     (val_add, ":friend_count", 1),
     (val_add, ":enemy_count", 1),

     (try_begin),
       (ge, ":friend_count", ":enemy_count"),
       (val_mul, ":friend_count", 100),
       (store_div, ":ratio", ":friend_count", ":enemy_count"),
       (store_sub, ":raw_advantage", ":ratio", 100),
     (else_try),
       (val_mul, ":enemy_count", 100),
       (store_div, ":ratio", ":enemy_count", ":friend_count"),
       (store_sub, ":raw_advantage", 100, ":ratio"),
     (try_end),

     (val_mul, ":player_party_tactics", 50),
     (val_mul, ":enemy_party_tactics", 50),
     (val_add, ":raw_advantage", ":player_party_tactics"),
     (val_sub, ":raw_advantage", ":enemy_party_tactics"),

     (assign, ":raw_mod_advantage", ":raw_advantage"),
     (val_add, ":raw_mod_advantage", 1000000),
     (val_mod, ":raw_mod_advantage", 100),
     (try_begin),
       (ge, ":raw_mod_advantage", 50),
       (assign, ":raw_mod_advantage", 1),
     (else_try),
       (assign, ":raw_mod_advantage", 0),
     (try_end),

     (try_begin),
       (lt, ":raw_advantage", 0),
       (val_sub, ":raw_mod_advantage", 1),
     (try_end),

     (val_div, ":raw_advantage", 100),
     (val_add, ":raw_advantage", ":raw_mod_advantage"),

     (assign, reg0, ":raw_advantage"),
    ]),


# script_check_enemies_nearby
# Input: none
# Output: none, fails when enemies are nearby
  ("check_enemies_nearby",
   [
       (get_player_agent_no, ":player_agent"),
       (agent_is_alive, ":player_agent"),
       (try_begin),
         (agent_is_defender, ":player_agent"),
         (assign, ":player_defender", 1),
       (else_try),
         (assign, ":player_defender", 0),
       (try_end),
       (agent_get_position, 1, ":player_agent"),
       (assign, ":result", 0),
       (try_for_agents,":cur_agent"),
         (neq, ":cur_agent", ":player_agent"),
         (agent_is_alive, ":cur_agent"),
         (agent_is_human, ":cur_agent"),
         (try_begin),
           (agent_is_defender, ":cur_agent"),
           (assign, ":agent_defender", 1),
         (else_try),
           (assign, ":agent_defender", 0),
         (try_end),
         (neq, ":player_defender", ":agent_defender"),
         (agent_get_position, 2, ":cur_agent"),
         (get_distance_between_positions, ":cur_distance", 1, 2),
         (le, ":cur_distance", 1500),
         (assign, ":result", 1),
       (try_end),
       (eq, ":result", 0),
    ]),
]
